#include <stdlib.h>
#include <unistd.h>
#include "http_connection.h"

void http_connection_init (http_connection_t *http_connection)
{
	http_connection->index = -1;
	http_connection->sd = -1;
	http_connection->fd = -1;

	http_connection->filesize = 0;
	http_connection->if_modified_since = -1;

	http_connection->connection_attempts = 0;

	buffer_init (&http_connection->buffer, 1024);

	http_connection->http_connection_state = READING_REQUEST;
	http_connection->request_state = 0;

	http_connection->http_method = NO_METHOD;
	buffer_init (&http_connection->path, 64);
	buffer_init (&http_connection->host, 32);
	buffer_init (&http_connection->authorization, 64);
	buffer_init (&http_connection->user_agent, 128);
	buffer_init (&http_connection->message_body, 4 * 1024);
	buffer_init (&http_connection->content_type, 64);

	http_connection->size_next_record = 0;
	http_connection->pending_current_record = 0;
	http_connection->fastcgi_state = 0;
	http_connection->added_empty_stdin = 0;

	buffer_init (&http_connection->range_header, 32);
	http_connection->parts = NULL;
	rangelist_init (&http_connection->rangelist);
	http_connection->current_range = 0;

	http_connection->major_number = 0;
	http_connection->minor_number = 0;
	http_connection->nCRLFs = 0;

	http_connection->message_header = NO_HEADER;
	http_connection->headers = 0;

	http_connection->token = 0;
	http_connection->end = 0;
	http_connection->offset = 0;

	http_connection->noffsets = 0;

	http_connection->content_length = -1;

	http_connection->sent = 0;
	http_connection->received = 0;

	http_connection->last_read_write = 0;

	http_connection->port = 0;

	http_connection->keep_alive = 0;
	http_connection->chunked = 0;

	http_connection->proxy_connection = 0;
}

void http_connection_free (http_connection_t *http_connection)
{
	size_t i;

	/* Close socket descriptor. */
	if (http_connection->sd != -1) {
		close (http_connection->sd);
	}

	/* Close file descriptor. */
	if (http_connection->fd != -1) {
		close (http_connection->fd);
	}

	/* Free buffer. */
	buffer_free (&http_connection->buffer);

	/* Free path. */
	buffer_free (&http_connection->path);

	/* Free host. */
	buffer_free (&http_connection->host);

	/* Free authorization. */
	buffer_free (&http_connection->authorization);

	/* Free User-Agent. */
	buffer_free (&http_connection->user_agent);

	/* Free message body. */
	buffer_free (&http_connection->message_body);

	/* Free Content-Type. */
	buffer_free (&http_connection->content_type);

	/* Free range header. */
	buffer_free (&http_connection->range_header);

	/* Remove parts. */
	if (http_connection->parts) {
		for (i = 0; i < http_connection->rangelist.used + 1; i++) {
			buffer_free (&(http_connection->parts[i]));
		}

		free (http_connection->parts);
		http_connection->parts = NULL;
	}

	/* Free range list. */
	rangelist_free (&http_connection->rangelist);
}

void http_connection_reset (http_connection_t *http_connection)
{
	size_t i;

	http_connection->index = -1;

	/* Close socket descriptor. */
	if (http_connection->sd != -1) {
		close (http_connection->sd);
		http_connection->sd = -1;
	}

	/* Close file descriptor. */
	if (http_connection->fd != -1) {
		close (http_connection->fd);
		http_connection->fd = -1;
	}

	http_connection->filesize = 0;
	http_connection->if_modified_since = -1;

	http_connection->connection_attempts = 0;

	if (http_connection->buffer.size > 2 * http_connection->buffer.buffer_increment) {
		buffer_free (&http_connection->buffer);
	} else {
		buffer_reset (&http_connection->buffer);
	}

	http_connection->http_connection_state = READING_REQUEST;
	http_connection->request_state = 0;

	http_connection->http_method = NO_METHOD;

	if (http_connection->path.size > http_connection->path.buffer_increment) {
		buffer_free (&http_connection->path);
	} else {
		buffer_reset (&http_connection->path);
	}

	if (http_connection->host.size > http_connection->host.buffer_increment) {
		buffer_free (&http_connection->host);
	} else {
		buffer_reset (&http_connection->host);
	}

	if (http_connection->authorization.size > http_connection->authorization.buffer_increment) {
		buffer_free (&http_connection->authorization);
	} else {
		buffer_reset (&http_connection->authorization);
	}

	if (http_connection->user_agent.size > http_connection->user_agent.buffer_increment) {
		buffer_free (&http_connection->user_agent);
	} else {
		buffer_reset (&http_connection->user_agent);
	}

	if (http_connection->message_body.size > http_connection->message_body.buffer_increment) {
		buffer_free (&http_connection->message_body);
	} else {
		buffer_reset (&http_connection->message_body);
	}

	if (http_connection->content_type.size > http_connection->content_type.buffer_increment) {
		buffer_free (&http_connection->content_type);
	} else {
		buffer_reset (&http_connection->content_type);
	}

	http_connection->size_next_record = 0;
	http_connection->pending_current_record = 0;
	http_connection->fastcgi_state = 0;
	http_connection->added_empty_stdin = 0;

	if (http_connection->range_header.size > http_connection->range_header.buffer_increment) {
		buffer_free (&http_connection->range_header);
	} else {
		buffer_reset (&http_connection->range_header);
	}

	if (http_connection->parts) {
		for (i = 0; i < http_connection->rangelist.used + 1; i++) {
			buffer_free (&(http_connection->parts[i]));
		}

		free (http_connection->parts);
		http_connection->parts = NULL;
	}

	if (http_connection->rangelist.size > 5) {
		rangelist_free (&http_connection->rangelist);
	} else {
		rangelist_reset (&http_connection->rangelist);
	}

	http_connection->current_range = 0;

	http_connection->major_number = 0;
	http_connection->minor_number = 0;
	http_connection->nCRLFs = 0;

	http_connection->message_header = NO_HEADER;
	http_connection->headers = 0;

	http_connection->token = 0;
	http_connection->end = 0;
	http_connection->offset = 0;

	http_connection->noffsets = 0;

	http_connection->content_length = -1;

	http_connection->sent = 0;
	http_connection->received = 0;

	http_connection->last_read_write = 0;

	http_connection->port = 0;

	http_connection->keep_alive = 0;
	http_connection->chunked = 0;

	http_connection->proxy_connection = 0;
}

void http_connection_reuse (http_connection_t *http_connection)
{
	size_t i;

	/* Close file descriptor. */
	if (http_connection->fd != -1) {
		close (http_connection->fd);
		http_connection->fd = -1;
	}

	http_connection->filesize = 0;
	http_connection->if_modified_since = -1;

	http_connection->connection_attempts = 0;

	/* Reset buffer. */
	buffer_reset (&http_connection->buffer);

	http_connection->http_connection_state = READING_REQUEST;
	http_connection->request_state = 0;

	http_connection->http_method = NO_METHOD;

	/* Reset path. */
	buffer_reset (&http_connection->path);

	/* Reset host. */
	buffer_reset (&http_connection->host);

	/* Reset authorization. */
	buffer_reset (&http_connection->authorization);

	/* Reset User-Agent. */
	buffer_reset (&http_connection->user_agent);

	/* Reset message body. */
	buffer_reset (&http_connection->message_body);

	/* Reset Content-Type.*/
	buffer_reset (&http_connection->content_type);

	http_connection->size_next_record = 0;
	http_connection->pending_current_record = 0;
	http_connection->fastcgi_state = 0;
	http_connection->added_empty_stdin = 0;

	/* Reset range header. */
	buffer_reset (&http_connection->range_header);

	/* Remove parts. */
	if (http_connection->parts) {
		for (i = 0; i < http_connection->rangelist.used + 1; i++) {
			buffer_free (&(http_connection->parts[i]));
		}

		free (http_connection->parts);
		http_connection->parts = NULL;
	}

	/* Reset range list. */
	rangelist_reset (&http_connection->rangelist);

	http_connection->current_range = 0;

	http_connection->major_number = 0;
	http_connection->minor_number = 0;
	http_connection->nCRLFs = 0;

	http_connection->message_header = NO_HEADER;
	http_connection->headers = 0;

	http_connection->token = 0;
	http_connection->end = 0;
	http_connection->offset = 0;

	http_connection->noffsets = 0;

	http_connection->content_length = -1;

	http_connection->port = 0;

	http_connection->keep_alive = 0;
	http_connection->chunked = 0;

	http_connection->proxy_connection = 0;
}
